﻿using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.Events;
using XLinq;

public class CopyMenu : MonoBehaviour
{

    public InputField urlInput;

    public Button enterURL;

    public Button openHTMLFile;

    public GameObject content;
    public GameObject menuWithGo, menuWithoutGo;

    bool cacheSize;
    Vector2 sizeOfMenuWithGo, sizeofMenuWithoutGo;

    public GameObject highlight;

    private Image highlight_image;

    [Space]
    public Button[] cut, copy, paste, pasteToGo, delete;

    List<Button> all = new List<Button>();

    public Color canClick = Color.black;
    public Color cantClick = Color.black;
    void Awake()
    {
        highlight_image = highlight.GetComponentInChildren<Image>();
    }

    // Use this for initialization
    void Start()
    {
        cut.ForLoop((c) => c.onClick.AddListener(MenuCut));
        copy.ForLoop((c) => c.onClick.AddListener(MenuCopy));
        paste.ForLoop((p) => p.onClick.AddListener(MenuPaste));
        pasteToGo.ForLoop((p) => p.onClick.AddListener(MenuPasteAndGo));
        delete.ForLoop((d) => d.onClick.AddListener(MenuDelete));

        LinqHelper.AllForLoop((b) =>
            {
                all.Add(b);
                if (b.GetComponent<Text>())
                    b.GetComponent<Text>().text = "    "+b.GetComponent<Text>().text;
            },
            cut, copy, paste, pasteToGo, delete);



        content.SetActive(false);



        ped = new PointerEventData(EventSystem.current);
        
    }

    List<RaycastResult> results = new List<RaycastResult>();
    PointerEventData ped;
    // Update is called once per frame
    void Update()
    {

        if (Input.GetMouseButtonUp(1))
        {
            RefreshPointerEnter();

            for (int i = 0; i < results.Count; i++)
            {
                var g = results[i].gameObject.GetComponent<Graphic>();

                if (g.raycastTarget)
                {
                    var t = g.transform;
                    InputField inf = t.GetComponent<InputField>();
                    while (inf == null && t.parent != null)
                    {
                        t = t.parent;
                        inf = t.GetComponent<InputField>();
                    }

                    if (inf != null)
                    {
                        if (EventSystem.current.currentSelectedGameObject != inf.gameObject)
                        {
                            inf.Select();
                            var tx = inf.text;
                            inf.selectionAnchorPosition = 0;
                            inf.selectionFocusPosition = tx.Length;
                        }

                        operating_target_inf = inf;
                        start_p = operating_target_inf.selectionAnchorPosition;
                        end_p = operating_target_inf.selectionFocusPosition;

                        RefreshMenuButtons();

                        if (inf == urlInput)
                        {
                            menuWithGo.SetActive(true);
                            menuWithoutGo.SetActive(false);
                        }
                        else
                        {
                            menuWithGo.SetActive(false);
                            menuWithoutGo.SetActive(true);
                        }

                        SetMenuPosition();
                        content.SetActive(true);
                    }

                    break;
                }
            }
        }

        else if (Input.GetMouseButtonDown(0))
        {
            if (content.activeSelf)
            {
                RefreshPointerEnter();

                var ind = MouseOverButtonIndexInAll();
                if (ind < 0)
                {

                    DelayDone(() =>
                        CloseContent()
                    );
                }
            }
        }
        else if (Input.GetMouseButtonUp(0))
        {
            if (content.activeSelf)
            {
                RefreshPointerEnter();

                DelayDone(() =>
                    CloseContent()
                );

            }

        }

        if (content.activeSelf)
        {
            RefreshPointerEnter();

            bool fail = true;

            var ind = MouseOverButtonIndexInAll();
            if (ind >= 0)
            {
                if (!highlight.activeSelf)
                {
                    highlight.SetActive(true);
                }
                if (all[ind].interactable)
                {
                    highlight_image.color = canClick;
                }
                else
                {
                    highlight_image.color = cantClick;
                }
                highlight.transform.position = all[ind].transform.position;
                fail = false;
            }


            if (fail)
            {
                highlight.SetActive(false);
            }
        }
    }

    void CheckMenuSize()
    {
        if (!cacheSize)
        {
            sizeOfMenuWithGo = (menuWithGo.transform as RectTransform).rect.size;
            sizeofMenuWithoutGo = (menuWithoutGo.transform as RectTransform).rect.size;
            cacheSize = true;
        }
    }

    void SetMenuPosition()
    {
        CheckMenuSize();

        Vector2 size = menuWithGo.activeSelf ? sizeOfMenuWithGo : sizeofMenuWithoutGo;
        Vector3 offset = new Vector3();
        if (Input.mousePosition.x < Screen.width - size.x)
        {
            offset.x = 1;
        }
        else
        {
            offset.x = Screen.width - size.x - Input.mousePosition.x;
        }

        if (Input.mousePosition.y > size.y)
        {
            offset.y = -1;
        }
        else
        {
            offset.y = size.y + 1;
        }
        

        transform.position = Input.mousePosition + offset;
    }

    int MouseOverButtonIndexInAll()
    {
        Button b;
        if (results.Count > 0 && (b = results[0].gameObject.GetComponent<Button>()))
        {
            var ind = all.IndexOf(b);
            return ind;
        }
        return -1;
    }

    void CloseContent()
    {
        content.SetActive(false);
    }

    void RefreshPointerEnter()
    {
        results.Clear();
        ped.position = Input.mousePosition;
        EventSystem.current.RaycastAll(ped, results);
    }

    InputField operating_target_inf;
    int start_p, end_p;

    void RefreshMenuButtons()
    {
        if (start_p != end_p)
        {
            cut.ForLoop((c) => c.interactable = true);
            copy.ForLoop((c) => c.interactable = true);
            delete.ForLoop((d) => d.interactable = true);
        }
        else
        {
            cut.ForLoop((c) => c.interactable = false);
            copy.ForLoop((c) => c.interactable = false);
            delete.ForLoop((d) => d.interactable = false);
        }
    }

    void SetCopy(string str)
    {
        GUIUtility.systemCopyBuffer = str;
    }

    string GetPaste()
    {
        return GUIUtility.systemCopyBuffer;
    }

    public void MenuCut()
    {
        string ori = operating_target_inf.text;

        var min_c = Mathf.Min(start_p, end_p);
        var max_cp1 = Mathf.Max(start_p, end_p);//plus 1
        
        string copyStr = ori.Substring(min_c, max_cp1 - min_c);

        SetCopy(copyStr);

        string split0 = ori.Substring(0, min_c);
        string split1 = "";
        if (max_cp1 < ori.Length)
        {
            split1 = ori.Substring(max_cp1, ori.Length - max_cp1);
        }

        operating_target_inf.text = split0 + split1;
    }

    public void MenuCopy()
    {
        var min_c = Mathf.Min(start_p, end_p);
        var max_cp1 = Mathf.Max(start_p, end_p);//plus 1

        string copy = operating_target_inf.text.Substring(min_c, max_cp1 - min_c);
        SetCopy(copy);
    }

    public void MenuPaste()
    {
        string copyStr = GetPaste();
        copyStr = copyStr.Replace("\r\n", "\n");
        copyStr = copyStr.Replace("\r", "\n");

        string ori = operating_target_inf.text;

        var min_c = Mathf.Min(start_p, end_p);
        var max_cp1 = Mathf.Max(start_p, end_p);//plus 1

        string split0 = ori.Substring(0, min_c);
        string split1 = "";
        if (max_cp1 < ori.Length)
        {
            split1 = ori.Substring(max_cp1, ori.Length - max_cp1);
        }

        operating_target_inf.text = split0 + copyStr + split1;
    }

    public void MenuPasteAndGo()
    {
        MenuPaste();

        enterURL.onClick.Invoke();
    }

    public void MenuDelete()
    {
        string ori = operating_target_inf.text;

        var min_c = Mathf.Min(start_p, end_p);
        var max_cp1 = Mathf.Max(start_p, end_p);//plus 1

        string split0 = ori.Substring(0, min_c);
        string split1 = "";
        if (max_cp1 < ori.Length)
        {
            split1 = ori.Substring(max_cp1, ori.Length - max_cp1);
        }

        operating_target_inf.text = split0 + split1;
    }

    public void DelayDone(UnityAction act)
    {
        StartCoroutine(_DelayDoSomething(act));
    }

    IEnumerator _DelayDoSomething(UnityAction act)
    {
        yield return null;
        if (act != null)
            act();
    }


}

namespace XLinq
{
    static class LinqHelper
    {
        public static void AllForLoop<T>(UnityAction<T> action, params IList<T>[] collections)
        {
            for (int i = 0; i < collections.Length; i++)
            {
                for (int j = 0; j < collections[i].Count; j++)
                {
                    action(collections[i][j]);
                }
            }
        }

        public static void ForLoop<T>(this IList<T> collection, UnityAction<T> action)
        {
            for (int i = 0; i < collection.Count; i++)
            {
                action(collection[i]);
            }
        }
    }
}
